#include <iostream>
#include <event2/event.h>
#include <event2/listener.h>
#include <csignal>
#include <cstring>

using namespace std;

void listen_cb(struct evconnlistener *e, evutil_socket_t s, struct sockaddr *a, int socklen, void *arg)
{
    cout << "listen_cb" << endl;
}

int main()
{
    // 忽略管道信号，发送数据给已关闭的socket
    if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
        return 1;

    // 创建配置上下文
    auto conf = event_config_new();
    if (!conf) {
        cout << "event conf new failed." << endl;
        return 1;
    }

    // 显示支持的网络模式 epoll poll select
//    auto method = event_get_supported_methods();
//    cout << "supported methods: " << endl;
//    for (int i = 0; method[i] != NULL; i++) {
//        cout << method[i] << endl;
//    }

    //   设置了 EV_FEATURE_FDS，其他特征就无法设置
    // EV_FEATURE_FDS 不支持epoll
    //event_config_require_features(conf, EV_FEATURE_FDS);

    // 设置网咯模型，使用select
    event_config_avoid_method(conf, "epoll");
    event_config_avoid_method(conf, "poll");

    auto base = event_base_new_with_config(conf);
    event_config_free(conf);
    if (base) {
        cout << "event init success." << endl;
        // 获取当前的网咯模型
        cout << "current method is " << event_base_get_method(base) << endl;


        auto f = event_base_get_features(base);
        if (f & EV_FEATURE_ET)
            cout << "EV_FEATURE_ET are supported" << endl;
        else
            cout << "EV_FEATURE_ET not supported" << endl;
        if (f & EV_FEATURE_O1)
            cout << "EV_FEATURE_O1 are supported" << endl;
        else
            cout << "EV_FEATURE_O1 not supported" << endl;
        if (f & EV_FEATURE_FDS)
            cout << "EV_FEATURE_FDS are supported" << endl;
        else
            cout << "EV_FEATURE_FDS not supported" << endl;
        if (f & EV_FEATURE_EARLY_CLOSE)
            cout << "EV_FEATURE_EARLY_CLOSE are supported" << endl;
        else
            cout << "EV_FEATURE_EARLY_CLOSE not supported" << endl;
    } else {
        cout << "event base new failed,exit." << endl;
        return 1;
    }

    // 监听端口
    sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(8000);

    // socket bind listen
    auto cv = evconnlistener_new_bind(base,
                                      listen_cb,
                                      base,
                                      LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE,
                                      10,
                                      reinterpret_cast<sockaddr *>(&sin),
                                      sizeof(sin));

    event_base_dispatch(base);

    if (cv)
        evconnlistener_free(cv);

    event_base_free(base);
    return 0;
}
